Fix rendering of theme parts on Windows XP
authorAlexander Larsson <alexl@redhat.com>
Fri, 9 Mar 2012 15:37:11 +0000 (16:37 +0100)
committerAlexander Larsson <alexl@redhat.com>
Fri, 9 Mar 2012 15:43:00 +0000 (16:43 +0100)
It seems XP doesn't handle drawing non-alpha theme parts
on alpha destinations. We fix this by using alpha bitmaps only when
needed.

However this means any non-drawn area by the theme part is now draw
black, so we must take more care to only draw where the theme part draws,
so we find the theme part size when available.

gtk/gtkcssimagewin32.c
gtk/gtkwin32theme.c
gtk/gtkwin32themeprivate.h

index 8c79fd6bb879d1529182de10ed054c6f0b347fe2..ca82a08f608d13d03325616ef6729dd02b6f1858 100644 (file)
@@ -33,21 +33,23 @@ gtk_css_image_win32_draw (GtkCssImage        *image,
 {
   GtkCssImageWin32 *wimage = GTK_CSS_IMAGE_WIN32 (image);
   cairo_surface_t *surface;
+  int dx, dy;
 
   surface = _gtk_win32_theme_part_create_surface (wimage->theme, wimage->part, wimage->state, wimage->margins,
-                                                 width, height);
+                                                 width, height, &dx, &dy);
   
   if (wimage->state2 >= 0)
     {
       cairo_surface_t *surface2;
       cairo_t *cr;
+      int dx2, dy2;
 
       surface2 = _gtk_win32_theme_part_create_surface (wimage->theme, wimage->part2, wimage->state2, wimage->margins,
-                                                      width, height);
+                                                      width, height, &dx2, &dy2);
 
       cr = cairo_create (surface);
 
-      cairo_set_source_surface (cr, surface2, 0, 0);
+      cairo_set_source_surface (cr, surface2, dx2 - dx, dy2-dy);
       cairo_paint_with_alpha (cr, wimage->over_alpha);
       
       cairo_destroy (cr);
@@ -55,8 +57,8 @@ gtk_css_image_win32_draw (GtkCssImage        *image,
       cairo_surface_destroy (surface2);
     }
 
-  cairo_set_source_surface (cr, surface, 0, 0);
-  cairo_pattern_set_extend (cairo_get_source (cr), CAIRO_EXTEND_PAD);
+  cairo_set_source_surface (cr, surface, dx, dy);
+  cairo_pattern_set_extend (cairo_get_source (cr), CAIRO_EXTEND_NONE);
   cairo_rectangle (cr, 0, 0, width, height);
   cairo_fill (cr);
 
index 35fd5db417a5a2cee25948422bd649047eb37e4c..b2931ed5585605e9359fa91e9efa24f90e07dad3 100644 (file)
@@ -184,27 +184,65 @@ _gtk_win32_theme_part_create_surface (HTHEME theme,
                                      int    state,
                                      int    margins[4],
                                      int    width,
-                                      int    height)
+                                      int    height,
+                                     int   *x_offs_out,
+                                     int   *y_offs_out)
 {
   cairo_surface_t *surface;
   GdkRGBA color;
   cairo_t *cr;
+  int x_offs;
+  int y_offs;
 #ifdef G_OS_WIN32
   HDC hdc;
   RECT rect;
+  SIZE size;
   HRESULT res;
+#endif
 
-  surface = cairo_win32_surface_create_with_dib (CAIRO_FORMAT_ARGB32, width, height);
-  hdc = cairo_win32_surface_get_dc (surface);
+  x_offs = margins[3];
+  y_offs = margins[0];
+
+  width -= margins[3] + margins[1];
+  height -= margins[0] + margins[2];
+
+#ifdef G_OS_WIN32
+  rect.left = 0;
+  rect.top = 0;
+  rect.right = width;
+  rect.bottom = height;
+
+  hdc = GetDC (NULL);
+  res = get_theme_part_size (theme, hdc, xp_part, state, &rect, 2, &size);
+  ReleaseDC (NULL, hdc);
+
+  if (res == S_OK)
+    {
+      x_offs += (width - size.cx) / 2;
+      y_offs += (height - size.cy) / 2;
   
-  rect.left = margins[3];
-  rect.top = margins[0];
-  rect.right = width - margins[1];
-  rect.bottom = height - margins[2];
+      width = size.cx;
+      height = size.cy;
+
+      rect.right = width;
+      rect.bottom = height;
+    }
+
+  if (is_theme_partially_transparent (theme, xp_part, state))
+    surface = cairo_win32_surface_create_with_dib (CAIRO_FORMAT_ARGB32, width, height);
+  else
+    surface = cairo_win32_surface_create_with_dib (CAIRO_FORMAT_RGB24, width, height);
+
+  hdc = cairo_win32_surface_get_dc (surface);
 
   res = draw_theme_background (theme, hdc, xp_part, state, &rect, &rect);
+
+  *x_offs_out = x_offs;
+  *y_offs_out = y_offs;
+
   if (res == S_OK)
     return surface;
+
 #else /* !G_OS_WIN32 */
   surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, width, height);
 #endif /* G_OS_WIN32 */
@@ -218,6 +256,9 @@ _gtk_win32_theme_part_create_surface (HTHEME theme,
 
   cairo_destroy (cr);
   
+  *x_offs_out = x_offs;
+  *y_offs_out = y_offs;
+
   return surface;
 }
 
index 4445f2dea694b83aaf0f9292ecc21e4bf99e44dc..309c53c778c53d1b9db42ee49f0a090a0dc20307 100644 (file)
@@ -44,7 +44,9 @@ cairo_surface_t *  _gtk_win32_theme_part_create_surface  (HTHEME       theme,
                                                           int          state,
                                                           int          margins[4],
                                                           int          width,
-                                                          int          height);
+                                                          int          height,
+                                                         int         *x_offs_out,
+                                                         int         *y_offs_out);
 
 int                _gtk_win32_theme_int_parse     (GtkCssParser      *parser,
                                                   GFile             *base,